Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't populate excluded fields while populating existing models history #381

Closed
wants to merge 7 commits into from
Closed

Don't populate excluded fields while populating existing models history #381

wants to merge 7 commits into from

Conversation

uadnan
Copy link

@uadnan uadnan commented Apr 29, 2018

Consider existing model, on which HistoricalRecords is added with some fields excluded,

 class MyModel(models.Model):
    name = models.CharField(max_length=100)
    created = models.DateTimeField(auto_now_add=True)
    modified = models.DateTimeField(auto_now=True)

    history = HistoricalRecords(excluded_fields=['created', 'modified'])

And here in this case, populate_history will still try to instantiate the model with created and modified value, that leads to this error:

TypeError: 'created' is an invalid keyword argument for this function

This pull request address above described issue and replaces #304

@codecov-io
Copy link

codecov-io commented Apr 29, 2018

Codecov Report

Merging #381 into master will increase coverage by 0.02%.
The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #381      +/-   ##
==========================================
+ Coverage   97.52%   97.54%   +0.02%     
==========================================
  Files          15       15              
  Lines         605      610       +5     
  Branches       78       80       +2     
==========================================
+ Hits          590      595       +5     
  Misses          9        9              
  Partials        6        6
Impacted Files Coverage Δ
...ple_history/management/commands/_populate_utils.py 100% <ø> (ø) ⬆️
simple_history/models.py 98.59% <100%> (+0.03%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 596b75c...316836b. Read the comment docs.

historical_instances = [
history_model(
history_date=getattr(instance, '_history_date', now()),
history_user=getattr(instance, '_history_user', None),
**{
field.attname: getattr(instance, field.attname)
for field in instance._meta.fields
if not excluded_fields & {field.name, field.attname}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why use field.attname here? In fields_included we only check on field.name: https://github.com/treyhunner/django-simple-history/blob/master/simple_history/models.py#L142

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rossmechanic Ok, I've updated the code to only have check on field.name

@uadnan
Copy link
Author

uadnan commented May 23, 2018

@rossmechanic would like to review this PR again?

@rossmechanic
Copy link
Collaborator

Yes going to review this week! @uadnan

attrs = {'__module__': self.module}
attrs = {
'__module__': self.module,
'excluded_fields': self.excluded_fields
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This prevents someone from using excluded_fields as a field_name, no?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or it will get overwritten by that field name, but either way it's not safe.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we add it to the Meta class of the historical model instead?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If that moved to meta class that will lead to exception by Django. If that fixed some how that will not be detected by Django migrator and lead to excluded fields being ignored within Django Migrations.

I'm adding a _ prefix to excluded_fields thus user can have a field with that name.

@rossmechanic
Copy link
Collaborator

@uadnan any update?

models.PollWithExcludeFields.history.all().delete()
management.call_command(self.command_name,
'tests.pollwithexcludefields', auto=True)
update_record = models.PollWithExcludeFields.history.all()[0]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update_record seems a bit misleading since no update actually happened. How about initial_history_record?

uadnan and others added 7 commits June 14, 2018 22:44
- tests the management command on an historical record which has excluded fields
- tests the excluded fields are retrieved from the current model instance
Previously, it was pre-loading directly related objects.
excluded_fields -> _history_excluded_fields
update_record -> initial_history_record
@uadnan
Copy link
Author

uadnan commented Jun 14, 2018

@rossmechanic Can you please have a look again?

@@ -1,13 +1,16 @@
Changes
=======

Unreleased
----------
- Fix TypeError on populate_history if excluded_fields are specified
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Want to add the PR number to this? (gh-381)

attrs = {'__module__': self.module}
attrs = {
'__module__': self.module,
'_history_excluded_fields': self.excluded_fields
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still don't love adding this on the model itself. Will think about this about and think about any cleaner solutions. Going to be merging some bulk_history_create updates anyway so this will need to be rebased. I'll let you know if I can think of any other way of doing this. Otherwise we'll go with this.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For reference, this is why we can't put excluded_fields on the meta class. So I'm fine with the current implementation.

poll = models.PollWithExcludeFields.objects.create(
question="Will this work?", pub_date=datetime.now())
models.PollWithExcludeFields.history.all().delete()
management.call_command(self.command_name,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add stderr=StringIO() and stdout=StringIO() here so the output isn't printed in the console when running tests

@rossmechanic
Copy link
Collaborator

@uadnan so I thought about this – Happy with this approach to the problem. Just need to rebase and make sure your test in test_commands.py doesn't print to the console. Then this is all good and I'm happy to merge. Let me know if you don't have time to rebase – If so, I can rebase it and merge it. Trying to get this in ASAP so I can do a micro release with the fix today.

@rossmechanic
Copy link
Collaborator

@uadnan I rebased this in #410. So going to close this PR and merge that one. Thanks for this fix!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants